package AggregationServer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Comparator;


public class AggregationServer {

    private int port;
    private String filePath;

    public AggregationServer(int port, String filePath) {
        this.port = port;
        this.filePath = filePath;
    }

    public void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("Aggregation Server start on port:"+port+" success!");
        while (true) {
            Socket socket = serverSocket.accept();
            handleRequest(socket);
        }
    }

    private synchronized void handleRequest(Socket socket) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        // parse request line
        String requestLine = reader.readLine();
        String[] parts = requestLine.split(" ");
        String method = parts[0];
        String path = parts[1];

        // parse request head
        String header;
        int contentLength = 0;
        while ((header = reader.readLine()) != null && !header.trim().isEmpty()) {
            if (header.startsWith("Content-Length:")) {
                int index = header.indexOf(":");
                if (index != -1) {
                    String length = header.substring(index + 1).trim();
                    contentLength = Integer.parseInt(length);
                }
            }
        }
        char[] body = new char[contentLength];
        reader.read(body, 0, contentLength);

        // transfer request body to String
        String requestBody = new String(body);
        System.out.println("Handleing "+method +" request.");

        // deal with request by request method
        if ("PUT".equals(method)) {
            // (...) deal with PUT request

            // read rquest body by Content-Length


            // TODO::  no content return 204
            if (requestBody.trim().equals("")) {
                // TODO:  Set response header and response code
                String response = "HTTP/1.1 204 No Content\r\n" +
                        "\r\n" ;
                socket.getOutputStream().write(response.getBytes());
            } else {
                //TODO: parse fail return 500
                boolean success = true;
                JSONObject weatherData = null;
                try {
                    // transfer String to JSON
                    weatherData = JSONObject.parseObject(requestBody);
                } catch (Exception e) {
                    // 设置响应头和响应码
                    String response = "HTTP/1.1 500 Internal Server Error\r\n" +
                            "Content-Type: text/html\r\n" +
                            "\r\n" +
                            "<html><body>Internal Server Error</body></html>";
                    socket.getOutputStream().write(response.getBytes());
                    success = false;
                    e.printStackTrace();
                }

                // TODO:  parse successful
                if (success) {
                    File file = new File(filePath);
                    try {
                        // create new file if  not exist
                        if (file.createNewFile()) {
                            System.out.println("File created: " + file.getName());
                            try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
                                JSONArray jsonArray = new JSONArray();
                                jsonArray.add(weatherData);
                                writer.write(jsonArray.toString());
                                // String response = "HTTP/1.1  201 - HTTP_CREATED OK\n\n";
                                // TODO:  Set response header and response code
                                String response = "HTTP/1.1 201 Created\r\n" +
                                        "Content-Type: text/html\r\n" +
                                        "\r\n" +
                                        "<html><body>The First Created</body></html>";
                                socket.getOutputStream().write(response.getBytes());
                            } catch (IOException e) {
                                // TODO:  Set response header and response code
                                String response = "HTTP/1.1 500 Internal Server Error\r\n" +
                                        "Content-Type: text/html\r\n" +
                                        "\r\n" +
                                        "<html><body>" + e.getMessage() + "</body></html>";
                                socket.getOutputStream().write(response.getBytes());
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println("File already exists.");
                            //read file and save it to String
                            String rawString = readData();
                            JSONArray jsonArray = JSONArray.parseArray(rawString);
                            //check the id whether exists in old file
                            boolean isExist = false;
                            for (int i = 0; i < jsonArray.size(); i++) {
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                if (jsonObject.getString("id").equals(weatherData.getString("id"))) {
                                    isExist = true;
                                    break;
                                }
                            }
                            if (!isExist) {
                                jsonArray.add(weatherData);
                            } else {
                                //update old data
                                for (int i = 0; i < jsonArray.size(); i++) {
                                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                                    if (jsonObject.getString("id").equals(weatherData.getString("id"))) {
                                        jsonArray.set(i, weatherData);
                                        break;
                                    }
                                }
                            }
                            try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
                                JSONArray sortedJsonArray = new JSONArray();
                                // TODO Keep the last 20 entries
                                jsonArray.sort(Comparator.comparing(data->((JSONObject)data).getLong("timestamp")).reversed());
                                int n= Math.min(jsonArray.size(), 20);
                                for (int i = 0; i <n ; i++) {
                                    sortedJsonArray.add(jsonArray.getJSONObject(i));
                                }
                                writer.write(sortedJsonArray.toString());
                                // String response = "HTTP/1.1  200 OK\n\n";
                                // TODO:  Set response header and response code
                                String response = "HTTP/1.1 200 OK\r\n" +
                                        "Content-Type: text/html\r\n" +
                                        "\r\n" +
                                        "<html><body>SUCCESS</body></html>";
                                socket.getOutputStream().write(response.getBytes());
                            } catch (IOException e) {
                                // TODO:  Set response header and response code
                                String response = "HTTP/1.1 500 Internal Server Error\r\n" +
                                        "Content-Type: text/html\r\n" +
                                        "\r\n" +
                                        "<html><body>" + e.getMessage() + "</body></html>";
                                socket.getOutputStream().write(response.getBytes());
                                e.printStackTrace();
                            }


                        }
                    } catch (IOException e) {
                        // TODO:  设置响应头和响应码
                        String response = "HTTP/1.1 500 Internal Server Error\r\n" +
                                "Content-Type: text/html\r\n" +
                                "\r\n" +
                                "<html><body>" + e.getMessage() + "</body></html>";
                        socket.getOutputStream().write(response.getBytes());
                        e.printStackTrace();
                    }

              /*    String response = "HTTP/1.1 200 OK\n\n";
                  socket.getOutputStream().write(response.getBytes());*/
                }
            }

        } else if ("GET".equals(method)) {
            // deat with GET request
            // read file and save it in String
            String rawString = readData();
            JSONArray jsonArray = JSONArray.parseArray(rawString);
            // String response = "HTTP/1.1 200 OK\n\n";
            // TODO:  Set response header and response code
            String response = "HTTP/1.1 200 OK\r\n" +
                    "Content-Type: text/html\r\n" +
                    "\r\n" +
                    jsonArray.toString();
            socket.getOutputStream().write(response.getBytes());
            //socket.getOutputStream().write(jsonArray.toString().getBytes());
        } else {
         // TODO:  Set response header and response code
            // 设置响应头和响应码
            String response = "HTTP/1.1 400 Bad Request\r\n" +
                    "Content-Type: text/html\r\n" +
                    "\r\n" +
                    "<html><body>Bad Request</body></html>";
            socket.getOutputStream().write(response.getBytes());
        }

        reader.close();
        socket.close();
    }

    private String readData() {
        String rawString = "";
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                rawString += line;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(rawString.equals("")){
            rawString="[]";
        }
        return rawString;
    }

    public static void main(String[] args) throws IOException {
        if (args.length < 1) {
            System.out.println("Usage: java AggregationServer <port>");
            return;
        }
        int port = Integer.parseInt(args[0]);
        new AggregationServer(port, "data.txt").start();
    }


}
